//Always used variables
float4x4 World;
float4x4 View;
float4x4 Projection;

//Ambient & Diffuse & Specular Lighting related variables
float3 AmbientLightColor;
float3 LightDirection;
float3 DiffuseLightColor;
float3 SpecularLightColor;
float4 SpecularColorPower;
float3 CameraPosition;

//Fog related variables
float3 FogColor;
float FogStart;
float FogEnd;

//Bump mapping variables (make changes to set these on the outside as in effect.parameters["***"].setValues(***);
float BumpConstant = 1;
texture NormalMap;
sampler2D bumpSampler = sampler_state {
    Texture = (NormalMap);
    MinFilter = Linear;
    MagFilter = Linear;
    AddressU = Wrap;
    AddressV = Wrap;
};
float3 halfVector = float3(1, 0, 0);

texture ModelTexture;
sampler2D textureSampler = sampler_state {
    Texture = (ModelTexture);
    MinFilter = Linear;
    MagFilter = Linear;
    AddressU = Wrap;
    AddressV = Wrap;
};

struct VertexShaderInput
{
    float4 Position  : POSITION0;  
	float3 Normal	 : NORMAL0; 
	float3 Tangent   : TANGENT0;
	float3 Binormal  : BINORMAL0;
	float2 TextureCoordinate : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position  : POSITION0;
	float3 Normal	 : TEXCOORD0;
	float3 View		 : TEXCOORD1;  
	float  Fog		 : TEXCOORD2;
	float3 Tangent   : TEXCOORD3;
    float3 Binormal  : TEXCOORD4;
	float2 TextureCoordinate : TEXCOORD5;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;
    
	float4 worldPosition = mul(input.Position, World);
    float4 viewPosition = mul(worldPosition, View);
    output.Position = mul(viewPosition, Projection);
	output.Normal = mul(input.Normal, World);
	output.View = CameraPosition - worldPosition;
	output.Fog = saturate((length(CameraPosition - worldPosition) - FogStart) / (FogEnd - FogStart));

	//new (changed worldinversetranspose with World
	output.Tangent = normalize(mul(input.Tangent, World));
    output.Binormal = normalize(mul(input.Binormal, World));
	output.TextureCoordinate = input.TextureCoordinate;

	return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
	float3 normal = normalize(input.Normal);
	float3 finalColor = float3(0, 0, 0);
	float3 view = normalize(input.View);
	
	float3 bump = BumpConstant * (tex2D(bumpSampler, input.TextureCoordinate) - (0.5, 0.5, 0.5));
    float3 bumpNormal = input.Normal + (bump.x * input.Tangent + bump.y * input.Binormal);
    bumpNormal = normalize(bumpNormal);

	float3 halfVector = normalize(view + LightDirection);
	float NdotH = saturate(dot(bumpNormal, halfVector));

	float specular = 0;
	if(NdotH != 0)
		specular += pow(NdotH, SpecularColorPower.w) * SpecularLightColor;

	finalColor += SpecularColorPower.xyz * specular;

	//set min value of diffuse to lightness of ambient lights color
	float3 diffuse = AmbientLightColor;

	//Calc Diffuse Light by using dot factor on Normal and light direction
	float NdotL = saturate(dot(bumpNormal, LightDirection));
	diffuse += NdotL * DiffuseLightColor;

	finalColor += diffuse;
	
	// Calculate the texture color
    float4 textureColor = tex2D(textureSampler, input.TextureCoordinate);
    textureColor.a = 1;

	finalColor = saturate(textureColor * diffuse + AmbientLightColor + specular);
	
	//Fog
	finalColor = lerp(finalColor, FogColor, input.Fog);
	
	return float4(finalColor, 1);
}

technique Technique1
{
    pass Pass1
    {
        // TODO: set renderstates here.

        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}